package com.lap.auth.adapter.driving.persistence.user.repository;

import com.lap.auth.adapter.driving.persistence.user.UserCache;
import com.lap.auth.adapter.driving.persistence.user.UserConverter;
import com.lap.auth.adapter.driving.persistence.user.mapper.UserMapper;
import com.lap.auth.adapter.driving.persistence.user.po.UserPo;
import com.lap.auth.domain.user.User;
import com.lap.auth.domain.user.repository.UserRepository;
import com.lap.framework.exception.OptimisticLockingFailureException;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;

@RequiredArgsConstructor
@Repository
public class UserRepositoryImpl implements UserRepository {

  private final UserConverter converter;
  private final UserMapper userMapper;

  @CachePut(value = UserCache.USER, key = "#user.id", condition = "#user.id != null")
  @Override
  public User save(User user) {
    UserPo userPo = converter.toPo(user);
    if (user.isNew()) {
      userMapper.insert(userPo);
    } else {
      int affectedRows = userMapper.updateById(userPo);
      if (affectedRows < 1) {
        throw new OptimisticLockingFailureException();
      }
    }
    return converter.toDomain(userPo);
  }

  @CacheEvict(value = UserCache.USER, key = "#id")
  @Override
  public int deleteById(Integer id) {
    return userMapper.deleteById(id);
  }

  @Cacheable(value = UserCache.USER, key = "#id", unless = "#result == null")
  @Override
  public Optional<User> findById(Integer id) {
    UserPo userPo = userMapper.selectById(id);
    return Optional.ofNullable(converter.toDomain(userPo));
  }

  @Cacheable(value = UserCache.USER, key = "#username", unless = "#result == null")
  @Override
  public Optional<User> findByUsername(String username) {
    UserPo userPo = userMapper.selectByUsername(username);
    return Optional.ofNullable(converter.toDomain(userPo));
  }
}
